﻿using Best.SmartCms.Domain;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Best.SmartCms.Core.Utility;
using Best.SmartCms.Domain.Common;
using Microsoft.EntityFrameworkCore;
using Best.SmartCms.Dao.Common;
using Best.SmartCms.Utility;

namespace Best.SmartCms.Dao
{
    /// <summary>
    ///  数据存储基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class BaseDao<T> where T : BaseDomain
    {

        private readonly MySqlDbContext _mySqlDbContext;

        protected string GetTypename()
        {
            return GetType().Name;
        }

        protected BaseDao(MySqlDbContext basicDbContext)
        {
            _mySqlDbContext = basicDbContext;
        }



        #region common oprations

        public T Add(T entity)
        {
            try
            {
                var stopwatch = Stopwatch.StartNew();
                entity.CreatedTime = DateTime.Now;
                var processResult = _mySqlDbContext.Set<T>().Add(entity);
                _mySqlDbContext.SaveChanges();
                stopwatch.Stop();
                return processResult.Entity;
            }
            catch (DbUpdateException ex)
            {
                if (ex.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".Add", ex.Message);
                    throw new DAOException(ex.Message);
                }
                if (ex.InnerException.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".Add", ex.InnerException.Message);
                    throw new DAOException(ex.InnerException.Message);
                }
                NLogManager.LogError(GetTypename() + ".Add", ex.InnerException.InnerException.Message);
                throw new DAOException(ex.InnerException.InnerException.Message);
            }
            catch (Exception ex)
            {
                NLogManager.LogError(GetTypename() + ".Add", ex.Message);
                throw new DAOException(ex.Message);
            }
        }


        /// <summary>
        /// 添加实体集合
        /// </summary>
        /// <param name="entities">实体集合</param>
        public void Add(IEnumerable<T> entities)
        {
            if (entities == null)
            {
                throw new ArgumentNullException(nameof(entities));
            }

            _mySqlDbContext.Set<T>().AddRange(entities);
            _mySqlDbContext.SaveChanges();
        }

        public int Update(T entity, List<string> updatePropertys = null)
        {
            try
            {
                var stopwatch = Stopwatch.StartNew();
                entity.UpdatedTime = DateTime.Now;
                if (updatePropertys == null)
                {
                    _mySqlDbContext.Set<T>().Attach(entity);
                    _mySqlDbContext.Entry(entity).State = EntityState.Modified;
                }
                else
                {
                    _mySqlDbContext.Set<T>().Attach(entity);
                    updatePropertys.ForEach(o =>
                    {
                        _mySqlDbContext.Entry(entity).Property(o).IsModified = true;
                    });
                }
                var rowNum = _mySqlDbContext.SaveChanges();
                NLogManager.LogDebug(GetTypename() + ".Update:cost is " + stopwatch.Elapsed);
                return rowNum;
            }
            catch (DbUpdateException ex)
            {
                if (ex.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".Update", ex.Message);
                    throw new DAOException(ex.Message);
                }
                if (ex.InnerException.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".Update", ex.InnerException.Message);
                    throw new DAOException(ex.InnerException.Message);
                }
                NLogManager.LogError(GetTypename() + ".Update", ex.InnerException.InnerException.Message);
                throw new DAOException(ex.InnerException.InnerException.Message);
            }
            catch (Exception ex)
            {
                NLogManager.LogError(GetTypename() + ".Update", ex.Message);
                throw new DAOException(ex.Message);
            }
        }

        public int Delete(T entity)
        {
            try
            {
                var stopwatch = Stopwatch.StartNew();
                _mySqlDbContext.Entry(entity).State = EntityState.Deleted;
                var rowNum = _mySqlDbContext.SaveChanges();
                NLogManager.LogDebug(GetTypename() + ".Delete:cost is " + stopwatch.Elapsed);
                return rowNum;
            }
            catch (DbUpdateException ex)
            {
                if (ex.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".Delete", ex.Message);
                    throw new DAOException(ex.Message);
                }
                if (ex.InnerException.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".Delete", ex.InnerException.Message);
                    throw new DAOException(ex.InnerException.Message);
                }
                NLogManager.LogError(GetTypename() + ".Delete", ex.InnerException.InnerException.Message);
                throw new DAOException(ex.InnerException.InnerException.Message);
            }
            catch (Exception ex)
            {
                NLogManager.LogError(GetTypename() + ".Delete", ex.Message);
                throw new DAOException(ex.Message);
            }
        }

        public T GetSingle(long id)
        {
            try
            {
                var stopwatch = Stopwatch.StartNew();
                var model = _mySqlDbContext.Set<T>().FirstOrDefault(o => o.Id == id);
                NLogManager.LogDebug(GetTypename() + ".GetSingle:cost is " + stopwatch.Elapsed);
                return model;
            }
            catch (DbUpdateException ex)
            {
                if (ex.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".GetSingle", ex.Message);
                    throw new DAOException(ex.Message);
                }
                if (ex.InnerException.InnerException == null)
                {
                    NLogManager.LogError(GetTypename() + ".GetSingle", ex.InnerException.Message);
                    throw new DAOException(ex.InnerException.Message);
                }
                NLogManager.LogError(GetTypename() + ".GetSingle", ex.InnerException.InnerException.Message);
                throw new DAOException(ex.InnerException.InnerException.Message);
            }
            catch (Exception ex)
            {
                NLogManager.LogError(GetTypename() + ".GetSingle", ex.Message);
                throw new DAOException(ex.Message);
            }
        }

        public List<T> FindAll()
        {
            var list = _mySqlDbContext.Set<T>().ToList();
            return list;
        }


        #endregion

    }

}
